using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using RTMP.SimpleClient.Helpers;

namespace RTMP.SimpleClient.Tests.MockServer
{
    /// <summary>
    /// RTMP 命令处理器
    /// </summary>
    public class CommandProcessor
    {
        private uint _nextStreamId = 1;
        private readonly object _streamIdLock = new object();

        /// <summary>
        /// 处理RTMP命令消息
        /// </summary>
        /// <param name="message">RTMP消息</param>
        /// <param name="clientStream">客户端网络流</param>
        /// <param name="commandReceived">命令接收事件回调</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>处理任务</returns>
        public async Task ProcessCommandAsync(RTMPMessage message, NetworkStream clientStream, 
            EventHandler<CommandReceivedEventArgs>? commandReceived, CancellationToken cancellationToken = default)
        {
            if (message.MessageTypeId != 20) // AMF0 Command Message
            {
                return;
            }

            try
            {
                // 解析AMF0命令
                var command = ParseAMF0Command(message.Data);
                Console.WriteLine($"[CommandProcessor] 收到命令: {command.CommandName}, TransactionId: {command.TransactionId}");

                // 触发命令接收事件
                commandReceived?.Invoke(this, new CommandReceivedEventArgs(
                    command.CommandName ?? "unknown", 
                    command.TransactionId, 
                    command.CommandObject, 
                    message.Data));

                // 根据命令类型进行处理
                switch (command.CommandName?.ToLower())
                {
                    case "connect":
                        await HandleConnectCommand(command, clientStream, cancellationToken);
                        break;
                    case "createstream":
                        await HandleCreateStreamCommand(command, clientStream, cancellationToken);
                        break;
                    case "play":
                        await HandlePlayCommand(command, clientStream, cancellationToken);
                        break;
                    case "publish":
                        await HandlePublishCommand(command, clientStream, cancellationToken);
                        break;
                    default:
                        Console.WriteLine($"[CommandProcessor] 未处理的命令: {command.CommandName}");
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[CommandProcessor] 处理命令失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 处理connect命令
        /// </summary>
        private async Task HandleConnectCommand(AMF0Command command, NetworkStream clientStream, CancellationToken cancellationToken)
        {
            Console.WriteLine($"[CommandProcessor] 处理Connect命令");

            // 发送Window Acknowledgement Size
            await SendWindowAckSize(clientStream, 2500000, cancellationToken);

            // 发送Set Peer Bandwidth
            await SendSetPeerBandwidth(clientStream, 2500000, cancellationToken);

            // 发送Set Chunk Size
            await SendSetChunkSize(clientStream, 4096, cancellationToken);

            // 发送Connect响应
            await SendConnectResponse(command.TransactionId, clientStream, cancellationToken);

            Console.WriteLine($"[CommandProcessor] Connect命令处理完成");
        }

        /// <summary>
        /// 处理createStream命令
        /// </summary>
        private async Task HandleCreateStreamCommand(AMF0Command command, NetworkStream clientStream, CancellationToken cancellationToken)
        {
            Console.WriteLine($"[CommandProcessor] 处理CreateStream命令");

            // 分配新的流ID
            uint streamId;
            lock (_streamIdLock)
            {
                streamId = _nextStreamId++;
            }

            // 发送CreateStream响应
            await SendCreateStreamResponse(command.TransactionId, streamId, clientStream, cancellationToken);

            Console.WriteLine($"[CommandProcessor] CreateStream命令处理完成, 分配流ID: {streamId}");
        }

        /// <summary>
        /// 处理play命令
        /// </summary>
        private async Task HandlePlayCommand(AMF0Command command, NetworkStream clientStream, CancellationToken cancellationToken)
        {
            Console.WriteLine($"[CommandProcessor] 处理Play命令");

            // 从命令参数中提取流名称
            string streamName = "unknown";
            if (command.Arguments != null && command.Arguments.Count > 0 && command.Arguments[0] is string name)
            {
                streamName = name;
            }

            // 发送StreamBegin
            await SendStreamBegin(clientStream, 1, cancellationToken);

            // 发送Play响应状态
            await SendPlayResponse(streamName, clientStream, cancellationToken);

            Console.WriteLine($"[CommandProcessor] Play命令处理完成, 流名称: {streamName}");
        }

        /// <summary>
        /// 处理publish命令
        /// </summary>
        private async Task HandlePublishCommand(AMF0Command command, NetworkStream clientStream, CancellationToken cancellationToken)
        {
            Console.WriteLine($"[CommandProcessor] 处理Publish命令");

            // 从命令参数中提取流名称和发布类型
            string streamName = "unknown";
            string publishType = "live";
            
            if (command.Arguments != null && command.Arguments.Count > 0)
            {
                if (command.Arguments[0] is string name)
                    streamName = name;
                if (command.Arguments.Count > 1 && command.Arguments[1] is string type)
                    publishType = type;
            }

            // 发送Publish响应状态
            await SendPublishResponse(streamName, publishType, clientStream, cancellationToken);

            Console.WriteLine($"[CommandProcessor] Publish命令处理完成, 流名称: {streamName}, 类型: {publishType}");
        }

        /// <summary>
        /// 解析AMF0命令
        /// </summary>
        private AMF0Command ParseAMF0Command(byte[] data)
        {
            var command = new AMF0Command();
            
            using var ms = new MemoryStream(data);
            using var reader = new BinaryReader(ms);

            try
            {
                // 读取命令名
                command.CommandName = ReadAMF0String(reader);

                // 读取事务ID  
                command.TransactionId = ReadAMF0Number(reader);

                // 读取命令对象
                command.CommandObject = ReadAMF0Value(reader);

                // 读取其他参数
                command.Arguments = new List<object?>();
                while (reader.BaseStream.Position < reader.BaseStream.Length)
                {
                    command.Arguments.Add(ReadAMF0Value(reader));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[CommandProcessor] AMF0解析错误: {ex.Message}");
            }

            return command;
        }

        /// <summary>
        /// 读取AMF0字符串
        /// </summary>
        private string? ReadAMF0String(BinaryReader reader)
        {
            if (reader.BaseStream.Position >= reader.BaseStream.Length)
                return null;

            byte type = reader.ReadByte();
            if (type != 0x02) // String type
                return null;

            // 字符串长度采用大端序
            ushort length = (ushort)((reader.ReadByte() << 8) | reader.ReadByte());
            if (length > reader.BaseStream.Length - reader.BaseStream.Position)
                return null;
                
            byte[] stringBytes = reader.ReadBytes(length);
            return System.Text.Encoding.UTF8.GetString(stringBytes);
        }

        /// <summary>
        /// 读取AMF0数字
        /// </summary>
        private double ReadAMF0Number(BinaryReader reader)
        {
            if (reader.BaseStream.Position >= reader.BaseStream.Length)
                return 0.0;

            byte type = reader.ReadByte();
            if (type != 0x00) // Number type
                return 0.0;

            if (reader.BaseStream.Length - reader.BaseStream.Position < 8)
                return 0.0;
                
            byte[] doubleBytes = reader.ReadBytes(8);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(doubleBytes);
            
            return BitConverter.ToDouble(doubleBytes, 0);
        }

        /// <summary>
        /// 读取AMF0值
        /// </summary>
        private object? ReadAMF0Value(BinaryReader reader)
        {
            if (reader.BaseStream.Position >= reader.BaseStream.Length)
                return null;

            byte type = reader.ReadByte();
            switch (type)
            {
                case 0x00: // Number
                    byte[] doubleBytes = reader.ReadBytes(8);
                    if (BitConverter.IsLittleEndian)
                        Array.Reverse(doubleBytes);
                    return BitConverter.ToDouble(doubleBytes, 0);

                case 0x01: // Boolean
                    return reader.ReadByte() != 0;

                case 0x02: // String
                    ushort length = (ushort)((reader.ReadByte() << 8) | reader.ReadByte());
                    byte[] stringBytes = reader.ReadBytes(length);
                    return System.Text.Encoding.UTF8.GetString(stringBytes);

                case 0x03: // Object
                    return ReadAMF0Object(reader);

                case 0x05: // Null
                    return null;

                case 0x06: // Undefined
                    return null;

                default:
                    return null;
            }
        }

        /// <summary>
        /// 读取AMF0对象
        /// </summary>
        private Dictionary<string, object?>? ReadAMF0Object(BinaryReader reader)
        {
            var obj = new Dictionary<string, object?>();

            while (reader.BaseStream.Position < reader.BaseStream.Length)
            {
                // 读取属性名长度
                ushort nameLength = (ushort)((reader.ReadByte() << 8) | reader.ReadByte());
                
                if (nameLength == 0)
                {
                    // 对象结束标记
                    byte endMarker = reader.ReadByte();
                    if (endMarker == 0x09)
                        break;
                }

                // 读取属性名
                byte[] nameBytes = reader.ReadBytes(nameLength);
                string propertyName = System.Text.Encoding.UTF8.GetString(nameBytes);

                // 读取属性值
                object? propertyValue = ReadAMF0Value(reader);
                obj[propertyName] = propertyValue;
            }

            return obj;
        }

        /// <summary>
        /// 发送Window Acknowledgement Size
        /// </summary>
        private async Task SendWindowAckSize(NetworkStream stream, uint windowSize, CancellationToken cancellationToken)
        {
            var data = new byte[4];
            data[0] = (byte)((windowSize >> 24) & 0xFF);
            data[1] = (byte)((windowSize >> 16) & 0xFF);
            data[2] = (byte)((windowSize >> 8) & 0xFF);
            data[3] = (byte)(windowSize & 0xFF);

            await SendControlMessage(stream, 5, data, cancellationToken); // Window Acknowledgement Size
        }

        /// <summary>
        /// 发送Set Peer Bandwidth
        /// </summary>
        private async Task SendSetPeerBandwidth(NetworkStream stream, uint bandwidth, CancellationToken cancellationToken)
        {
            var data = new byte[5];
            data[0] = (byte)((bandwidth >> 24) & 0xFF);
            data[1] = (byte)((bandwidth >> 16) & 0xFF);
            data[2] = (byte)((bandwidth >> 8) & 0xFF);
            data[3] = (byte)(bandwidth & 0xFF);
            data[4] = 0x02; // Dynamic

            await SendControlMessage(stream, 6, data, cancellationToken); // Set Peer Bandwidth
        }

        /// <summary>
        /// 发送Set Chunk Size
        /// </summary>
        private async Task SendSetChunkSize(NetworkStream stream, uint chunkSize, CancellationToken cancellationToken)
        {
            var data = new byte[4];
            data[0] = (byte)((chunkSize >> 24) & 0xFF);
            data[1] = (byte)((chunkSize >> 16) & 0xFF);
            data[2] = (byte)((chunkSize >> 8) & 0xFF);
            data[3] = (byte)(chunkSize & 0xFF);

            await SendControlMessage(stream, 1, data, cancellationToken); // Set Chunk Size
        }

        /// <summary>
        /// 发送控制消息
        /// </summary>
        private async Task SendControlMessage(NetworkStream stream, byte messageType, byte[] data, CancellationToken cancellationToken)
        {
            // 构造chunk header (简化版本，使用chunk stream ID 2)
            var header = new byte[12];
            header[0] = 0x02; // chunk stream ID 2, format 0
            // timestamp (3 bytes) = 0
            header[4] = (byte)((data.Length >> 16) & 0xFF);
            header[5] = (byte)((data.Length >> 8) & 0xFF);
            header[6] = (byte)(data.Length & 0xFF);
            header[7] = messageType;
            // message stream ID (4 bytes) = 0

            // 发送header + data
            await stream.WriteAsync(header, 0, header.Length, cancellationToken);
            await stream.WriteAsync(data, 0, data.Length, cancellationToken);
        }

        /// <summary>
        /// 发送Connect响应
        /// </summary>
        private async Task SendConnectResponse(double transactionId, NetworkStream stream, CancellationToken cancellationToken)
        {
            // 创建_result响应
            var response = RTMPCommandHelper.CreateCommandHeader("_result", transactionId);
            
            // 添加响应对象
            var responseObj = new Dictionary<string, object>
            {
                ["fmsVer"] = "FMS/3,5,7,7009",
                ["capabilities"] = 31.0,
                ["mode"] = 1.0
            };

            var statusObj = new Dictionary<string, object>
            {
                ["level"] = "status",
                ["code"] = "NetConnection.Connect.Success",
                ["description"] = "Connection succeeded.",
                ["data"] = responseObj,
                ["objectEncoding"] = 0.0
            };

            var body = RTMPCommandHelper.CreateCommandBody(responseObj, statusObj);
            var fullResponse = RTMPCommandHelper.CombineHeaderAndBody(response, body);

            await SendAMF0Command(stream, fullResponse, cancellationToken);
        }

        /// <summary>
        /// 发送CreateStream响应
        /// </summary>
        private async Task SendCreateStreamResponse(double transactionId, uint streamId, NetworkStream stream, CancellationToken cancellationToken)
        {
            var response = RTMPCommandHelper.CreateCommandHeader("_result", transactionId);
            var body = RTMPCommandHelper.CreateCommandBody(null, (double)streamId);
            var fullResponse = RTMPCommandHelper.CombineHeaderAndBody(response, body);

            await SendAMF0Command(stream, fullResponse, cancellationToken);
        }

        /// <summary>
        /// 发送StreamBegin
        /// </summary>
        private async Task SendStreamBegin(NetworkStream stream, uint streamId, CancellationToken cancellationToken)
        {
            var data = new byte[6];
            data[0] = 0x00; data[1] = 0x00; // User Control Message - StreamBegin
            data[2] = (byte)((streamId >> 24) & 0xFF);
            data[3] = (byte)((streamId >> 16) & 0xFF);
            data[4] = (byte)((streamId >> 8) & 0xFF);
            data[5] = (byte)(streamId & 0xFF);

            await SendControlMessage(stream, 4, data, cancellationToken); // User Control Message
        }

        /// <summary>
        /// 发送Play响应
        /// </summary>
        private async Task SendPlayResponse(string streamName, NetworkStream stream, CancellationToken cancellationToken)
        {
            // 发送onStatus响应
            var statusObj = new Dictionary<string, object>
            {
                ["level"] = "status",
                ["code"] = "NetStream.Play.Start",
                ["description"] = $"Started playing {streamName}.",
                ["details"] = streamName
            };

            var onStatusCommand = RTMPCommandHelper.CreateCommandHeader("onStatus", 0);
            var onStatusBody = RTMPCommandHelper.CreateCommandBody(null, statusObj);
            var fullOnStatus = RTMPCommandHelper.CombineHeaderAndBody(onStatusCommand, onStatusBody);

            await SendAMF0Command(stream, fullOnStatus, cancellationToken);
        }

        /// <summary>
        /// 发送Publish响应
        /// </summary>
        private async Task SendPublishResponse(string streamName, string publishType, NetworkStream stream, CancellationToken cancellationToken)
        {
            // 发送onStatus响应
            var statusObj = new Dictionary<string, object>
            {
                ["level"] = "status",
                ["code"] = "NetStream.Publish.Start",
                ["description"] = $"Started publishing {streamName}.",
                ["details"] = streamName
            };

            var onStatusCommand = RTMPCommandHelper.CreateCommandHeader("onStatus", 0);
            var onStatusBody = RTMPCommandHelper.CreateCommandBody(null, statusObj);
            var fullOnStatus = RTMPCommandHelper.CombineHeaderAndBody(onStatusCommand, onStatusBody);

            await SendAMF0Command(stream, fullOnStatus, cancellationToken);
        }

        /// <summary>
        /// 发送AMF0命令
        /// </summary>
        private async Task SendAMF0Command(NetworkStream stream, byte[] commandData, CancellationToken cancellationToken)
        {
            // 构造chunk header for AMF0 command (message type 20)
            var header = new byte[12];
            header[0] = 0x03; // chunk stream ID 3, format 0
            // timestamp (3 bytes) = 0
            header[4] = (byte)((commandData.Length >> 16) & 0xFF);
            header[5] = (byte)((commandData.Length >> 8) & 0xFF);
            header[6] = (byte)(commandData.Length & 0xFF);
            header[7] = 20; // AMF0 Command Message
            // message stream ID (4 bytes) = 0

            await stream.WriteAsync(header, 0, header.Length, cancellationToken);
            await stream.WriteAsync(commandData, 0, commandData.Length, cancellationToken);
        }
    }

    /// <summary>
    /// AMF0命令结构
    /// </summary>
    public class AMF0Command
    {
        public string? CommandName { get; set; }
        public double TransactionId { get; set; }
        public object? CommandObject { get; set; }
        public List<object?>? Arguments { get; set; }
    }
}